/**********************************************************
 *
 *  Copyright (c) 2003  SeikoEpson Inc
 *  All Rights Reserved
 *
 *  File name : p2t.c
 *  Function  :
 *        Source file for tan() routine
 *        Computes the 'tangent' for the given angle (in radians)
 *        This file is copied from math.lib of 
 *                  CC33 tool(CC33v40.exe + CCPA45.exe, 
 *                  math of ansilib33v25 )
 *
 *  original file's Revision  :
 *      No description
 *  Revision  :
 *      2003/04/06    IrumaSoft M.Takeishi   1.st design
 *
 **********************************************************/
#include <f_math.h>
#include <errno.h>
#include <f_smcvals.h>

#define	INVPI	  1.27323954473516268f            // 4/pi
#define	P0	 -0.1306820264754825668269611177e+5f
#define	P1	  0.1055970901714953193602353981e+4f
#define	P2	 -0.1550685653483266376941705728e+2f
#define	P3	  0.3422554387241003435328470489e-1f
#define	P4	  0.3386638642677172096076369e-4f
#define	Q0	 -0.1663895238947119001851464661e+5f
#define	Q1	  0.4765751362916483698926655581e+4f
#define	Q2	 -0.1555033164031709966900124574e+3f


float
f_tan( float arg )
{
	float	x;
	char	sign;
	char	flag;

	FLT_LNG   sfArg;

	/* NaN or INF returns NaN. */
	sfArg._F = arg;
	if ( (sfArg.st._LL & 0x7f800000 ) == 0x7f800000 ) {
		errno = EDOM;
		return f_NAN._F;
	}


	flag = 0;
	sign = 1;
	if( arg < 0.0f )
	{
		arg = -arg;
		sign = -1;
	}

	arg = arg * INVPI;   /* overflow? */
	x = f_modf( arg, &arg );	/* From here we don't need the value of 'arg' anymore */
				/* So we use 'arg' for other purposes */
	switch( (int)arg % 4 )
	{
	case 1:
		x = 1.0f - x;
		flag = 1;
		break;
	case 2:
		sign = -sign;
		flag = 1;
		break;
	case 3:
		x = 1.0f - x;
		sign = -sign;
		break;
	}

	arg = x * x;
	arg = ( ( ( ( ( P4 * arg + P3 ) * arg + P2 ) * arg + P1 ) * arg + P0 ) * x ) /
			( ( ( arg + Q2 ) * arg + Q1 ) * arg + Q0 );

	if( flag == 1 )
	{
		if( arg == 0.0f )
		{
			errno = ERANGE;
			if ( sign > 0 )
				return( F_HUGE_V );
			return( -F_HUGE_V );
		}
		arg = 1.0f / arg;
	}

	if( sign == 1 )
		return( arg );
	else
		return( -arg );
}


